﻿using System.IO;
using System.Net.Sockets;
using System.Text;

namespace Azure.Online.Proxy.Server {
    public class HttpServerContext {

        private readonly Stream _stream;

        private HttpServerRequest _request;
        private HttpServerResponse _response;

        public HttpServerContext(Socket socket) {
            //_stream = new LoggingStream(new NetworkStream(socket), new MemoryStream(), new MemoryStream());
            _stream = new NetworkStream(socket);
            ReadRequest();
        }

        public HttpServerRequest Request {
            get { return _request; }
        }


        public HttpServerResponse Response {
            get { return _response; }
        }

        private void ReadRequest() {
            _request = new HttpServerRequest(this, _stream);
            var requestLine = ReadLine();
            var args = requestLine.Split(' ');
            _request.Verb = args[0];
            _request.Path = args[1];
            _request.Version = args[2];

            string headerLine = string.Empty;
            do {
                headerLine = ReadLine();
                if (!string.IsNullOrWhiteSpace(headerLine)) {
                    var headerValueIndex = headerLine.IndexOf(':');
                    var name = headerLine.Substring(0, headerValueIndex).Trim();
                    var value = headerLine.Substring(headerValueIndex + 1).Trim();
                    _request.Headers[name] = value;
                }
            } while (headerLine != string.Empty);

            _response = new HttpServerResponse(this, _stream);
        }

        private string ReadLine() {
            var sb = new StringBuilder();
            while (true) {
                var bt = _stream.ReadByte();
                if (bt == 13) {
                    bt = _stream.ReadByte();
                    if (bt == 10) {
                        return sb.ToString();
                    } else {
                        sb.Append((char)13);
                        sb.Append((char)bt);
                    }
                } else {
                    sb.Append((char)bt);
                }
            }
        }
    }

    public class LoggingStream : Stream {
        private readonly Stream _primary;
        private readonly Stream _read;
        private readonly Stream _write;

        public LoggingStream(Stream primary, Stream read, Stream write) {
            _primary = primary;
            _read = read;
            _write = write;
        }

        public override void Flush() {
            _primary.Flush();
        }

        public override long Seek(long offset, SeekOrigin origin) {
            throw new System.NotImplementedException();
        }

        public override void SetLength(long value) {
            throw new System.NotImplementedException();
        }

        public override int Read(byte[] buffer, int offset, int count) {
            var read = _primary.Read(buffer, offset, count);
            _read.Write(buffer, offset, read);
            return read;
        }

        public override void Write(byte[] buffer, int offset, int count) {
            _primary.Write(buffer, offset, count);
            _write.Write(buffer, offset, count);
        }

        public override bool CanRead {
            get { return _primary.CanRead; }
        }

        public override bool CanSeek {
            get { throw new System.NotImplementedException(); }
        }

        public override bool CanWrite {
            get { return _primary.CanWrite; }
        }

        public override long Length {
            get { throw new System.NotImplementedException(); }
        }

        public override long Position { get; set; }
    }
}
